/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include "S_Object.h"

#include "底层绘图/底层绘图框架.h"
#include "core/shader_std.h"
#include "core/网格辅助计算.h"

#include <几何计算.h>

/*
* 
* 骨骼
*	|____
* 物体	|
*	|__网格
*/

#define DEF_网格主数据层 1

#define DEF_物体动画曲线(c) ((S_动画曲线组*)c->ptr_userData)






typedef enum : uint32 {
	e_变换关系_保持偏移,
	e_变换关系_继承,
	
}E_父级变换关系;

struct S_物体变换 : public S_Object {
	Mat44f		m_矩阵;
	S_Tranform	m_变换;
	//__m512		m_Mat;

	void		f_set矩阵(const float32* mat);
};


typedef struct {
	int32 是否独立缩放;
	float32 Z缩放;
	float32 Z偏移;
	float32 Z;
}S_单色材质属性;


class C_骨骼管理 {
public:
	static std::set<S_骨架*> m_骨骼容器;
	C_骨骼管理();
	~C_骨骼管理();
};




#define DEF_物体动画曲线组	S_List*
#define DEF_物体骨骼Prt		S_Tree*
#define DEF_骨骼组(b)		((S_Tree*)(b))
#define DEF_骨骼(b)			((S_骨架*)((b)->ptr_userData))



typedef void(*fp_物体数据更新函数)(void* data);
typedef void(*fp_物体变换生成回调)(S_物体* ob, Mat44f* 矩阵, const Mat44f* 父级变换);
typedef void(*fp_更新物体变换回调)(S_物体* ob, const Mat44f* 父级变换);



struct S_物体 : public S_Object {
	S_设备环境  m_Ctx;

	S_Tranform	m_变换;
	uint32      m_实例ID;
	E_物体类型  m_附属类型;

	Mat44f		m_全局缩放矩阵;
	Mat44f		m_旋转矩阵;
	
	std::vector<S_Object*>	m_扩展属性;

	std::vector<S_网格包>	m_网格模型;
	S_多边形*				m_多边形;
	
	bool		m_是否实例;
	bool		m_根实例;
	//bool		m_无实例物体;
	
	float32		m_深度偏移;
	
	
	uint8			m_网格拾取元素;
	E_父级变换关系	m_父级变换关系;
	S_RGBA8UI		m_颜色;


	S_GPU内存块 m_变换矩阵;
	S_GPU内存块 m_光追实例加速结构;
	S_GPU内存块 m_光追顶层加速结构;


	S_GPU内存块 m_物体属性;
	std::map<DEF_WString, S_GPU内存块*> m_实例自定义属性区间偏移;
	S_GPU内存块 m_自定义属性索引;


	std::vector<uint32>			m_实例材质ID;
	std::vector<S_GPU内存块>	m_实例颜色;
	
	
	

	//DEF_物体动画曲线组	m_动画曲线;
	S_曲线通道*	m_位置;
	S_曲线通道*	m_旋转;
	S_曲线通道*	m_缩放;
	float32		m_TimeOffset;
	//S_物体*			m_骨骼;

	S_骨架*		m_骨架;

	S_Cube		m_包围盒;
	S_Bounding  m_Bound;
	//S_GPU内存块 m_包围盒_GpuMem;

	

	uint16		m_DataNum;
	void**		m_Data;

	bool		m_isUpdate;
	bool		m_isUpdateMatrix;
	
	bool		m_渲染;
	bool		m_销毁;
	
	uint32		m_视口显示模式;
	uint16		m_渲染模式;


	fp_物体变换生成回调	mf_变换回调更新;
	fp_更新物体变换回调 mf_更新变换;


	//static float64 g_前一帧;
	float64 g_当前帧;
	static bool		   g_更新曲线关键帧;

	//================= 向全局内存分配过渡 =====================
	
	//static std::vector<S_板载缓存*> g_物体颜色;

	//static S_板载缓存* g_骨骼长度;
	static S_板载缓存* g_骨骼姿态;
	//static S_板载缓存* g_骨骼变换;


	//废弃
	static S_板载缓存* g_物体属性;
	bool		m_UpdateGPU参数布局;
	uint32      m_变换ID;


	//同时控制深度控制
	S_板载缓存*	m_独立缩放;
	//S_板载缓存* m_间接;
	S_VkDrawIndirectCommand        m_PickIndirect;
	S_VkDrawIndexedIndirectCommand m_IndexeIndirect;
	//S_GPU参数布局*	m_GPU参数布局;
	//S_GPU内存块 m_物体网格属性;

	S_物体(E_物体类型 type, uint32 id_name=0);
	~S_物体();

	//S_Object*	f_get(uint32 key);
	//S_Object*	f_get子类对象(uint32 key);
	void		f_set位置(float32 x, float32 y, float32 z);
	void		f_set旋转(float32 x, float32 y, float32 z);
	void		f_set缩放(float32 x, float32 y, float32 z);
	void		f_set位置(const vec3& xyz) { m_变换.position = xyz; m_isUpdate = true;}
	void		f_set旋转(const vec3& xyz) { m_变换.rotation = xyz; m_isUpdate = true;}
	void		f_set缩放(const vec3& xyz) { m_变换.scale = xyz; m_isUpdate = true;}

	void		f_set位置(const vec3& xyz, uint32 实例);
	void		f_set旋转(const vec3& xyz, uint32 实例);
	void		f_set缩放(const vec3& xyz, uint32 实例);

	vec3		f_get位置();
	vec3		f_get旋转();
	vec3		f_get缩放();
	vec4		f_get四元数();
	//std::vector<C_Mat44>	f_get矩阵(uint32 ID);
	std::vector<Mat44f>		f_get矩阵2(uint32 ID);
	//C_Mat44		f_get矩阵() const;
	Mat44f		f_get矩阵2() const;

	virtual		void		f_set矩阵(const Mat44f* mat);
	virtual		void		f_set矩阵(const Mat44f* mat, uint32);
	virtual		void		f_set矩阵mt(const Mat44f* mat) {}
	
	virtual		void		f_set变换(const void* mat, uint32 id) {}
	
	void		f_setData(void* data, uint16 loc = 0);
	void		f_setDataNum(uint16 num);
	virtual		std::vector<S_物体*>	f_创建实例(uint32 num);
	

	void		f_set碰撞类型();
	void		f_set碰撞形状();


	//virtual		void		f_Update(S_Object* 摄像机);
	virtual		void		f_Update(Mat44f* c, Mat44f* 父级变换);
	virtual		void		f_绘制(S_渲染参数& 摄像机);


	void f_打开可视通道(uint8 通道);
	void f_关闭可视通道(uint8 通道);
	void f_构建底层加速结构();


	
};


class C_物体缓存列队数据 {

protected:
	S_物体* m_物体;

public:
	C_物体缓存列队数据(S_物体* 物体) : m_物体(物体) {}
	virtual void f_更新属性();

};



struct S_骨节 {
	uint64					m_Type;
	std::vector<S_物体*>	m_关联骨骼;

	vec3					m_骨节初始尾坐标;
	float32					m_封套大小;
};


struct EngineAPI_EXPORT S_渲染对象 : public S_Object {
	S_物体* m_物体;
	uint32	m_物体光遮罩;
	uint8	m_场景遮罩;
	uint8	m_物体遮罩;

	S_渲染对象() : S_Object(E_物体类型::t_渲染物体) {
		m_物体光遮罩 = 0;
		m_场景遮罩 = 1;
		m_物体遮罩 = 1;
		//m_场景遮罩 = f_alloc_FlagBitsUI8Prop(nullptr, L"场景遮罩", 1);
		//m_场景遮罩.m_私有 = true;
	}

	void f_选择(bool 选择) {
		m_选中 = 选择;
		m_物体->m_选中 = 选择;
	}
};




typedef struct {
	S_设备环境			m_Ctx;

	S_光追后端*			m_光追后端;

	uint32				m_灯光类型;
	S_物体*				m_灯光;

	//S_纹理**			m_阴影图;
	//uint32				m_阴影图数量;
	S_纹理组*			m_阴影图;
	S_帧缓存组*			m_帧缓存;

	S_GPU内存块			m_灯光数据;
	S_GPU内存块			m_灯光阴影矩阵;



	fp_物体数据更新函数	mf_Update;
}S_灯光场景数据;

typedef struct {
	int32	实例ID;
	float32	相交宽度;
}S_实例拾取信息;

typedef struct {
	S_Mesh* 网格;
	uint32	实例ID;
	float32	相交宽度;
}S_网格拾取信息;




struct S_GL立即模式 : public S_物体 {
	//S_MeshBuf	m_几何体;
	S_GL立即模式(S_设备环境& ctx);


	void glBegin(E_填充模式 模式);
	void glEnd();

	void glVertex(const vec3& v);
	void glColor(const S_RGBA8UI& c);
	void glNormal(const vec3& n);
	void glCoord(const vec2& t);

	void glMatrixPush();
	void glMatrixPop();
	void glClear();


	void f_绘制(S_渲染参数& 渲染参数);

private:
	uint32		m_Mask;
	uint32		m_Count;
	S_设备环境& m_Ctx;

	S_物体*		m_当前物体;

	std::vector<S_物体*> m_Data;
};




typedef void(*fp_创建物体几何数据)(S_物体* ob, S_设备环境& ctx);


template<typename T>
auto f_me_网格常量推送初始化 = [](S_网格包& me){
	f_df_创建常量推送<T>(me.m_常量推送, E_着色阶段::e_顶点着色);
};

template<typename T>
S_网格包 f_ob_创建网格包(S_Mesh* me, S_材质管线* 管线) {
	S_网格包 pack;
	pack.m_Mesh = me;
	pack.m_多维材质槽.push_back(管线);
	pack.m_深度偏移 = 0;

	f_me_网格常量推送初始化<T>(pack);
	return pack;
};

void f_ob_销毁网格包(S_网格包& 网格包);


template<typename T>
auto f_ob_setData = [](S_物体* ob, S_Mesh* me, uint8 loc) -> S_网格包& {
	ob->m_网格模型[loc].m_Mesh = me;
	f_me_网格常量推送初始化<T>(ob->m_网格模型[loc]);
	return ob->m_网格模型[loc];
};

template<typename T>
auto f_ob_addData = [](S_物体* ob, S_Mesh* me, S_材质管线* 管线) -> S_网格包& {
	ob->m_网格模型.push_back({});
	auto& pack = ob->m_网格模型.back();
	pack.m_Mesh = me;
	pack.m_多维材质槽.push_back(管线);
	
	f_me_网格常量推送初始化<T>(pack);
	return pack;
};




template<typename T>
auto f_me_网格推送常量 = [](S_网格包& me) -> T& {
	return f_df_推送常量<T>(me.m_常量推送);
};




void on_物体变换生成(S_物体* ob, Mat44f* 矩阵, const Mat44f* 父级变换);



EngineAPI_EXPORT S_物体* f_get物体(uint32 id_name);
EngineAPI_EXPORT uint32	f_ob_getObType(S_物体* ob);

//EngineAPI_EXPORT void f_Ob_打开可视通道(uint8 通道);
//EngineAPI_EXPORT void f_Ob_关闭可视通道(uint8 通道);

EngineAPI_EXPORT void f_ob_绘制所有元素(S_物体* ob, S_渲染参数 渲染参数);
EngineAPI_EXPORT void f_ob_绘制单个元素(S_物体* ob, S_渲染参数 渲染参数, uint32 绘制元素, bool 多维子元素 = false);
EngineAPI_EXPORT void f_ob_绘制单个元素(S_物体* ob, S_渲染参数 渲染参数);
EngineAPI_EXPORT void f_ob_绘制选择元素(S_物体* ob, S_渲染参数 渲染参数, uint32 绘制元素);


EngineAPI_EXPORT void	f_ob_创建矩阵(S_物体* ob, uint32 num = 1);
EngineAPI_EXPORT void	f_ob_添加矩阵(S_物体* ob, uint32 插入位置 = -1);
EngineAPI_EXPORT void	f_ob_删除矩阵(S_物体* ob, uint32 loc = -1, uint32 num = 0);
EngineAPI_EXPORT void	f_ob_清除矩阵(S_物体* ob, uint32 num=1);

Inline void	f_ob_set矩阵(S_物体* ob, const Mat44f& mat) {
	f_buf_Mat44_at(ob->m_变换矩阵, ob->m_实例ID) = mat;
}
EngineAPI_EXPORT void f_ob_set矩阵(S_物体* ob, const Mat44f& mat, uint32 实例ID);
EngineAPI_EXPORT void f_ob_set矩阵(S_物体* ob, const Mat44f* mat, uint32 num);
EngineAPI_EXPORT void f_ob_set颜色(S_物体* ob, const uint32* color, uint32 num, uint32 槽 = 0);

EngineAPI_EXPORT void f_ob_绘制元素(S_物体* ob, S_Mesh* me, uint32 绘制元素, S_渲染参数& 渲染参数/*着色器布局改进后删除此参数*/, bool 多维子元素 = false);
//EngineAPI_EXPORT void f_ob_阴影绘制元素(S_物体* ob, S_Mesh* me, uint32 绘制元素, S_渲染参数& 渲染参数, bool 多维子元素);


EngineAPI_EXPORT S_物体*	f_ob_创建网格物体(S_设备环境 ctx);
EngineAPI_EXPORT Mat44f		f_ob_get实例变换矩阵(S_物体* Obj, uint32 ID);
EngineAPI_EXPORT Mat44f		f_ob_get变换矩阵(const S_物体* Ob, uint32 ID);
EngineAPI_EXPORT Mat44f		f_ob_get父对象变换矩阵(S_物体* Obj, uint32 depth, bool 包含顶层 = false);
EngineAPI_EXPORT S_Cube		f_ob_get包围盒(const Mat44f& mat, const S_Bounding& bound);

mat4 f_ob_getMatrix(const S_物体* ob, uint32 ID);


EngineAPI_EXPORT S_Bounding	f_ob_get世界包围盒(S_物体* ob, uint32 槽, uint32 实例);
EngineAPI_EXPORT vec3		f_ob_get世界中心(S_物体* ob, uint32 槽);
EngineAPI_EXPORT uint32		f_ob_get中心和(S_物体* ob, vec3& 中心和);

EngineAPI_EXPORT E_物体类型	f_ob_get实例父类型(S_物体* ob);
EngineAPI_EXPORT S_物体*	f_ob_get实例父对象(S_物体* ob);

vec3 f_ob_get全局旋转(S_物体* ob, vec3 旋转方向, uint32 实例);


Inline vec3 f_ob_get实例对象坐标(S_物体* ob, uint32 实例) {
	return (static_cast<S_物体*>(ob->m_子物体[实例]))->m_变换.position;
}
Inline vec3 f_ob_get对象世界坐标(S_物体* ob) {
	return f_buf_Mat44_at(ob->m_变换矩阵, ob->m_实例ID) * vec3{0,0,0};
}

Inline bool f_ob_isUpdate(S_物体* ob) {
	if (ob->m_父对象) {
		ob->m_isUpdate |= ((S_物体*)(ob->m_父对象))->m_isUpdate;
	}
}

EngineAPI_EXPORT void		f_ob_步进时间帧(float32 f);
EngineAPI_EXPORT void		f_ob_set步进时间帧(float64 f);

EngineAPI_EXPORT Mat44f		f_ob_构建XYZ变换矩阵euler(const S_物体* ob);
EngineAPI_EXPORT Mat44f		f_ob_构建XYZ变换矩阵euler(const vec3& rot);

Inline S_多边形* f_ob_from多边形(S_物体* ob) {
	assert(ob->m_Type == E_物体类型::t_多边形);
	return (S_多边形*)ob->m_UserData;
}

void f_ob_添加更新缓存列队(std::unique_ptr<C_物体缓存列队数据>&& data);
void f_ob_更新缓存列队();


EngineAPI_EXPORT S_骨骼IK*	f_ob_创建IK();
EngineAPI_EXPORT void		f_ob_销毁IK(S_骨骼IK* ik);
EngineAPI_EXPORT S_骨骼IK**	f_ob_添加IK(S_骨架* 骨骼, uint16 IK数量);

EngineAPI_EXPORT S_骨架*	f_ob_创建骨架();
EngineAPI_EXPORT void		f_ob_销毁骨节(S_骨架* 骨架);
EngineAPI_EXPORT S_骨架*	f_ob_from骨架(const S_物体* froObj, uint32 loc = 0);

EngineAPI_EXPORT S_骨骼*	f_ob_创建骨骼(S_物体* ob, float32 长度 = 1);
EngineAPI_EXPORT S_物体*	f_ob_创建骨骼(S_物体* 父物体, S_设备环境& ctx, float32 长度 = 1);

Inline S_骨骼* f_ob_from骨骼(const S_物体* froObj) {
	assert(froObj->m_UserData);
	return (S_骨骼*)froObj->m_UserData;
}
Inline S_骨节* f_ob_from骨节(S_骨骼* 骨骼) {
	return (S_骨节*)骨骼->m_骨节B->m_UserData;
}
//Inline S_骨节* f_ob_from骨节(S_物体* 骨节) {
//	return (S_骨节*)骨节->m_UserData;
//}
Inline S_骨节* f_ob_from骨节(const S_物体* 骨骼) {
	switch (骨骼->m_Type) {
		case E_物体类型::t_骨骼: return (S_骨节*)(f_ob_from骨骼(骨骼)->m_骨节B->m_UserData);
		case E_物体类型::t_骨节:
		case E_物体类型::t_实例:
			return (S_骨节*)骨骼->m_UserData;
		default:
			break;
	}
	return nullptr;
}
Inline vec3 f_ob_骨骼初始方向(float32 长度) {
	return { 0, 0, 长度 };
}

Inline S_封套 f_ob_get骨骼封套(S_骨骼* 骨骼) {
	S_封套 封套;
	
	封套.m_长度 = 骨骼->m_长度;
	封套.m_方向 = 骨骼->m_方向;
	封套.m_端点 = 骨骼->m_初始头坐标;

	封套.m_封套S内半径 = 骨骼->m_封套S内半径;
	封套.m_封套E内半径 = 骨骼->m_封套E内半径;
	封套.m_封套S外半径 = 骨骼->m_封套S外半径;
	封套.m_封套E外半径 = 骨骼->m_封套E外半径;

	return 封套;
}



EngineAPI_EXPORT S_物体*	f_ob_创建实例(S_物体* froObj = nullptr);
Inline uint32	f_ob_实例数量(S_物体* ob) {
	return ob->m_子物体.size();
}


EngineAPI_EXPORT void		f_ob_ge骨节坐标(S_物体* 根骨骼, vec3* 骨节, const Mat44f* 骨骼变换矩阵, const float32* 骨骼长度, const Mat44f& 父级变换);

EngineAPI_EXPORT vec3		f_ob_计算骨骼IK点(S_物体* ob, bool 尾部);
EngineAPI_EXPORT vec3		f_ob_计算骨骼IK中点(S_骨骼IK* IK);
EngineAPI_EXPORT void		f_ob_从骨节更新编辑骨骼(
										S_物体* 根骨骼, 
										vec3* 骨节, 
										const float32* 骨骼长度, 
										Mat44f* 骨骼物体变换矩阵, 
										const vec4& 父骨骼旋转, 
										const Mat44f& 父矩阵, 
										const vec3& s, 
										float32 l
									);



EngineAPI_EXPORT void		f_ob_准备解算IK关联骨骼(S_骨骼IK* IK);
EngineAPI_EXPORT void		f_ob_准备解算IK关联骨骼(S_物体* ob);
EngineAPI_EXPORT void		f_ob_解算IK骨节步进坐标(S_骨骼IK* IK, const vec3& 父物体坐标偏移, const Mat44f& mat);
EngineAPI_EXPORT void		f_ob_修正IK骨节距离(S_物体* ob);

EngineAPI_EXPORT void		f_ob_解算骨骼IK(S_物体* ob);
EngineAPI_EXPORT void		f_ob_从骨节更新骨骼(S_物体* 骨架);
EngineAPI_EXPORT void		f_ob_从骨节构建骨骼(S_物体* 根骨骼, S_物体* 骨节, const vec4& 父骨骼旋转, const float32 父骨骼长度);

EngineAPI_EXPORT void		f_ob_从骨骼更新骨节(S_物体* 骨架物体);
EngineAPI_EXPORT void		f_ob_骨节复位(S_物体* 骨架物体);
EngineAPI_EXPORT vec4		f_ob_骨骼旋转计算(S_骨骼* 骨骼, S_骨骼* 子骨骼);

EngineAPI_EXPORT void		f_ob_构建骨骼变换GPU数据(S_骨架* 骨架, const S_物体* 骨架物体, const Mat44f& mat);

Inline std::vector<S_Object*>& f_ob_get骨架骨节(S_物体* 骨架物体) {
	return 骨架物体->m_子物体.back()->m_子物体;
}

EngineAPI_EXPORT void f_ob_销毁网格数据(S_物体* ob);
EngineAPI_EXPORT void f_ob_计算网格包围盒(S_物体* ob);

Inline bool f_ob_显示模式是否开启(S_物体* ob, uint32 位) {
	
	bool open = (ob->m_视口显示模式 & 1 << 位) && (ob->m_视口显示模式 & 65536 << 位);
	if (!open) {
		if (位 == E_物体网格元素类型::e_MT_面) {
			位 = E_物体网格元素类型::e_MT_光照;
			open = (ob->m_视口显示模式 & 1 << 位) && (ob->m_视口显示模式 & 65536 << 位);
		}
	}
	return open;
}

Inline void f_ob_设置反弹场景和遮罩类型(S_物体* ob, uint32 场景ID, uint32 遮罩类型) {
	//ob->m_反弹场景_遮罩类型 = 场景ID<<16 | 遮罩类型;
}

EngineAPI_EXPORT void f_mesh_构建网格属性参数(S_物体* ob, S_Mesh* me, uint32 ObType);

EngineAPI_EXPORT void f_ob_骨骼物体变换生成(S_物体* ob, Mat44f* 矩阵, const Mat44f* 父级变换);



EngineAPI_EXPORT S_渲染层*	f_ob_创建渲染层(S_设备环境& ctx);
EngineAPI_EXPORT void		f_ob_销毁渲染层(S_渲染层* 层);
EngineAPI_EXPORT void		f_ob_设置渲染层数(S_渲染层* 渲染层, uint32 渲染层数量);


//void f_ob_构建物体实例加速结构(S_物体* ob, S_渲染层& 渲染层, uint8 场景遮罩, uint32 场景遮罩和物体遮罩, uint32& 实例偏移);
EngineAPI_EXPORT S_Mesh* f_ob_get光追网格(S_物体* ob);

EngineAPI_EXPORT void f_ob_构建底层光追加速结构(S_物体* ob);
EngineAPI_EXPORT void f_ob_构建底层层光追加速结构(S_渲染对象** renderOb, uint32 num);
EngineAPI_EXPORT void f_ob_构建底层层光追加速结构(S_OBArray* obs);
EngineAPI_EXPORT void f_ob_构建底层层光追加速结构(std::vector<S_Object*>& obs);
EngineAPI_EXPORT void f_ob_构建底层层光追加速结构(std::map<std::wstring, S_Object*>& obs);

EngineAPI_EXPORT void f_ob_更新光追底层加速结构(S_设备环境& ctx);

EngineAPI_EXPORT void f_ob_构建光追实例加速结构(S_物体* ob, S_渲染层& 渲染层, uint8 场景遮罩, uint32 场景遮罩和物体遮罩, uint32& 实例偏移);



